﻿using System;
using System.Text;
using ReadyApps.Common;

namespace ReadyApps.Wiki
{
    /// <summary>
    /// Represents a single set of possible privileges.
    /// </summary>
    [Serializable]
    public sealed class EffectivePermissions
    {
        #region Variables

        private WikiPermissions permissions;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets a value indicating whether the view page privilege is
        /// enabled.
        /// </summary>
        public bool ViewPage
        {
            get { return GetPermission(WikiPermissions.ViewPage); }
            set { SetPermission(WikiPermissions.ViewPage, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the edit page privilege is
        /// enabled.
        /// </summary>
        public bool EditPage
        {
            get { return GetPermission(WikiPermissions.EditPage); }
            set { SetPermission(WikiPermissions.EditPage, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the create page privilege is
        /// enabled.
        /// </summary>
        public bool CreatePage
        {
            get { return GetPermission(WikiPermissions.CreatePage); }
            set { SetPermission(WikiPermissions.CreatePage, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the create folder privilege is
        /// enabled.
        /// </summary>
        public bool CreateFolder
        {
            get { return GetPermission(WikiPermissions.CreateFolder); }
            set { SetPermission(WikiPermissions.CreateFolder, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the edit permissions privilege
        /// is enabled.
        /// </summary>
        public bool EditPermissions
        {
            get { return GetPermission(WikiPermissions.EditPermissions); }
            set { SetPermission(WikiPermissions.EditPermissions, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the manage revisions privilege
        /// is enabled.
        /// </summary>
        public bool ManageRevisions
        {
            get { return GetPermission(WikiPermissions.ManageRevisions); }
            set { SetPermission(WikiPermissions.ManageRevisions, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the manage publishing privilege
        /// is enabled.
        /// </summary>
        public bool ManagePublishing
        {
            get { return GetPermission(WikiPermissions.ManagePublishing); }
            set { SetPermission(WikiPermissions.ManagePublishing, value); }
        }

        /// <summary>
        /// Gets the privileges that are enabled for a non-security-enabled site.
        /// </summary>
        public static EffectivePermissions NonSecurityEnabledPermissions
        {
            get
            {
                return new EffectivePermissions()
                {
                    ViewPage = true,
                    EditPage = true,
                    CreatePage = true,
                    CreateFolder = true,
                    ManageRevisions = true
                };
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Creates a new <see cref="EffectivePermissions"/> object with all privileges
        /// disabled.
        /// </summary>
        public EffectivePermissions()
        {
            permissions = WikiPermissions.None;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Merges another <see cref="EffectivePermissions"/> with the existing privilege
        /// settings and an optional mask of privileges.
        /// </summary>
        /// <param name="applyPermissions">The <see cref="EffectivePermissions"/> to merge
        /// with this set.</param>
        /// <param name="applyMask">The optional privilege mask.</param>
        public void Apply(EffectivePermissions applyPermissions, WikiPermissions applyMask = WikiPermissions.AllPrivileges)
        {
            permissions |= (applyPermissions.permissions & applyMask);
        }

        #endregion

        #region Overrides

        /// <summary>
        /// Converts the object state into a readable format.
        /// </summary>
        /// <returns>The object state in a readable format.</returns>
        public override string ToString()
        {
            TraceManager.BeginMethod(TraceComponent.EffectivePermissions, "ToString");

            StringBuilder contents = new StringBuilder("EffectivePermissions{");

            bool hasContents = false;
            if (ViewPage)
            {
                hasContents = true;
                contents.Append("ViewPage");
            }

            if (EditPage)
            {
                if (hasContents)
                {
                    contents.Append("|");
                }
                else
                {
                    hasContents = true;
                }
                contents.Append("EditPage");
            }

            if (CreatePage)
            {
                if (hasContents)
                {
                    contents.Append("|");
                }
                else
                {
                    hasContents = true;
                }
                contents.Append("CreatePage");
            }

            if (CreateFolder)
            {
                if (hasContents)
                {
                    contents.Append("|");
                }
                else
                {
                    hasContents = true;
                }
                contents.Append("CreateFolder");
            }

            if (EditPermissions)
            {
                if (hasContents)
                {
                    contents.Append("|");
                }
                else
                {
                    hasContents = true;
                }
                contents.Append("EditPermissions");
            }

            if (ManageRevisions)
            {
                if (hasContents)
                {
                    contents.Append("|");
                }
                else
                {
                    hasContents = true;
                }
                contents.Append("ManageRevisions");
            }

            if (ManagePublishing)
            {
                if (hasContents)
                {
                    contents.Append("|");
                }
                else
                {
                    hasContents = true;
                }
                contents.Append("ManagePublishing");
            }

            contents.Append("}");

            TraceManager.EndMethod(TraceComponent.EffectivePermissions, "ToString");
            return contents.ToString();
        }

        /// <summary>
        /// Compares the <see cref="EffectivePermissions"/> to another object and checks for
        /// equality.
        /// </summary>
        /// <param name="obj">The object to compare to the effective permissions</param>
        /// <returns><c>True</c> if the compared object has the same value, <c>false</c>
        /// otherwise.</returns>
        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            EffectivePermissions other = (EffectivePermissions)obj;
            return permissions == other.permissions;
        }

        /// <summary>
        /// Gets the unique hashcode of the object.
        /// </summary>
        /// <returns>The unique hashcode of the object.</returns>
        public override int GetHashCode()
        {
            int hash = 13;
            hash = (hash * 7) + ViewPage.GetHashCode();
            hash = (hash * 7) + EditPermissions.GetHashCode();
            return hash;
        }

        #endregion

        #region Private Methods

        private bool GetPermission(WikiPermissions permissionToGet)
        {
            return (permissions & permissionToGet) == permissionToGet;
        }

        private void SetPermission(WikiPermissions permissionToSet, bool value)
        {
            if (value)
            {
                permissions |= permissionToSet;
            }
            else
            {
                if ((permissions & permissionToSet) == permissionToSet)
                {
                    permissions ^= permissionToSet;
                }
            }
        }

        #endregion
    }
}
